package drds.configuration.db.table_mapping;

import drds.configuration.common.Constants;
import drds.configuration.db.JdbcUtil;
import drds.configuration.db.datasource.DataSourceIdToDataSourceConfigMapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;


public class TableInfoBuilder {

    private static Logger log = LoggerFactory.getLogger(TableInfoBuilder.class);

    public static void buildModelClassToTableInfoMap() throws SQLException {
        for (Entry<String, List<TableInfo>> entry : DataSourceIdToDataSourceConfigMapContext.getDataSourceIdToTableInfoListMap().entrySet()) {
            //
            DataSource masterDataSource = DataSourceIdToDataSourceConfigMapContext.dataSourceIdToDataSourceConfigMap.get(entry.getKey()).getDataSource();
            List<TableInfo> tableInfoList = DataSourceIdToDataSourceConfigMapContext.dataSourceIdToTableInfoListMap.get(entry.getKey());
            //
            buildModelClassToTableInfoMap(entry.getKey(), masterDataSource, tableInfoList);
        }
    }

    /**
     * 最简单的说法就是根据所有表名建立字段对应信息
     */
    public static void buildModelClassToTableInfoMap(String groupDataSourceId, DataSource dataSource, List<TableInfo> tableInfoList) throws SQLException {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            /**
             * 暂时就只有表名,主键,所对应的Model类
             */
            for (TableInfo tableInfo : tableInfoList) {
                log.info("table info :" + tableInfo.getTableName());
                try {
                    tableInfo = buildTableInfo(tableInfo, connection);
                    //
                    //进行数据库字段和实体类类型校验
                    checkFieldTypeWithDataBaseColumnType(tableInfo);
                    //
                    ModelClassToTableInfoMap.addTableInfo(tableInfo.getModelClass(), tableInfo);
                } catch (Exception e) {
                    log.error(e.getMessage());
                    e.printStackTrace();
                    throw new RuntimeException("构建模型:" + tableInfo.getModelClass().getName() + "和表:" + tableInfo.getTableName() + "之间映射关系失败" + e);
                }
            }
        } finally {
            JdbcUtil.close(connection);
        }
        //对每个表进行基础字段校验,如果不一致则需要修改


    }

    /**
     * @param tableInfo 暂时只有表名 主键 模型类<br/>
     * @return 含有其他字段的TableInfo实例
     */
    private static TableInfo buildTableInfo(TableInfo tableInfo, Connection connection) throws SQLException {
        log.debug("buildTableInfo-Table:" + tableInfo.getTableName() + "	Modle:" + tableInfo.getModelClass().getName());
        /**
         * 利用select * from tableName查出该表所有的字段信息<br/>
         */
        String sql = Model.sql.buildSqlForTableInfo(tableInfo.getTableName());
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        int columnCount = resultSetMetaData.getColumnCount();
        if (columnCount == 0) {
            throw new IllegalArgumentException("表" + tableInfo.getTableName() + "没有字段信息");
        }
        if (Constants.devMode) {
            log.info("tableName:" + tableInfo.getTableName() + "列数是" + columnCount);
        }
        for (int i = 1; i <= columnCount; i++) {
            String columnName = resultSetMetaData.getColumnName(i);
            String columnClassName = resultSetMetaData.getColumnClassName(i);
            if (Constants.devMode) {
                log.info("withColumnName:" + columnName + "," + columnClassName + ":" + columnClassName);
            }
            if (Boolean.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Boolean.class);
                continue;
            }
            if (Short.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Short.class);
                continue;
            }
            if (Integer.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Integer.class);
                continue;
            }
            if (Long.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Long.class);
                continue;
            }
            if (Float.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Float.class);
                continue;
            }
            if (Double.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, Double.class);
                continue;
            }
            if (String.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, String.class);
                continue;
            }
            if (BigDecimal.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.math.BigDecimal.class);
                continue;
            }
            if (java.math.BigInteger.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.math.BigInteger.class);
                continue;
            }
            if (java.util.Date.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.util.Date.class);
                continue;
            }
            if (java.sql.Date.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.sql.Date.class);
                continue;
            }
            if (java.sql.Time.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.sql.Time.class);
                continue;
            }
            if (java.sql.Timestamp.class.getName().equals(columnClassName)) {
                tableInfo.addColumnInfo(columnName, java.sql.Timestamp.class);
                continue;
            }
            throw new RuntimeException("不支持其他类型");
        }
        resultSet.close();
        statement.close();
        //
        if (Constants.devMode) {
            //System.out.println(Long.MAX_VALUE);
            //9223372036854775807
            //0922 3372 0368 5477 5807
            log.info("表:" + tableInfo.getTableName() + "字段名-字段java类型");
            for (String columnName : tableInfo.getColumnNameToClassTypeMap().keySet()) {
                Class classType = tableInfo.getColumnNameToClassTypeMap().get(columnName);
                log.info("columnName:" + columnName + "=" + classType.getName());
            }
        }
        return tableInfo;
    }

    public static void checkFieldTypeWithDataBaseColumnType(TableInfo tableInfo) {
        Map<String, Class<?>> fieldColumnNameToClassTypeMap = tableInfo.fieldColumnNameToClassTypeMap;
        Map<String, Class<?>> columnNameToClassTypeMap = tableInfo.columnNameToClassTypeMap;
        if (fieldColumnNameToClassTypeMap.size() != columnNameToClassTypeMap.size()) {
            log.error("fieldColumnNameToClassTypeMap.size():" + fieldColumnNameToClassTypeMap.size() + ",columnNameToClassTypeMap.size():" + columnNameToClassTypeMap.size());
            throw new RuntimeException("表" + tableInfo.getModelClass().getName() + "属性和数据库表(" + tableInfo.getTableName() + ")字段个数不一致");
        }
        for (Map.Entry<String, Class<?>> entry : columnNameToClassTypeMap.entrySet()) {
            if (!entry.getValue().getName().equals(fieldColumnNameToClassTypeMap.get(entry.getKey()).getName())) {
                throw new RuntimeException("表" + tableInfo.getModelClass().getName() + "属性和数据库表(" + tableInfo.getTableName() + ")比较过程中,字段\"" + entry.getKey() + "\"类型不一致");
            }
        }
    }


}
